use std::fmt;
use std::sync::Arc;
use std::sync::atomic::AtomicUsize;

use parking_lot::Mutex;

use super::{exec::TaskScheduler, mspc_scheduler::MspcTaskAttr};

use super::exec::TaskExecutor;
use super::mspc_scheduler::MpscTaskScheduler;

#[derive(Debug, Clone)]
pub enum TestTask2 {
    Generate,
    Roll(Vec<u8>),
    Select(u128, u128),
    Max(u128),
}

impl TestTask2 {

}

#[derive(Debug, Clone)]
pub enum TestTaskError { }

impl fmt::Display for TestTaskError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "test task error")
    }
}

impl std::error::Error for TestTaskError { }

const GENERATE_LEN:usize = 1000;

impl TestTask2 {
    fn exec<S:crate::exec::TaskScheduler<Self>>(&self, ctx:Option<&mut u128>, sender:&S::Sender, task_counter:Arc<AtomicUsize>) -> Result<(), TestTaskError> {
        match self {
            TestTask2::Generate => {
                let mut seed = 1u128;
                for _ in 0..GENERATE_LEN {
                    let mut data = vec![0u8;4096];
                    for i in 0..4096 {
                        data[i] = (((seed * 1341410813) % 5422352) & 255) as u8;
                        seed += 1;
                    }
                    S::send_with_count(sender, TestTask2::Roll(data), &task_counter);
                }
            }
            TestTask2::Roll(data) => {
                let mut max_feature1 = 0;
                let mut max_feature2 = 0;
                for &byte in data {
                    let feature1 = ((byte as u128 * 21238214) % 839341) & 65536;
                    let feature2 = ((byte as u128 * 78131941) % 913417) & 65536;
                    max_feature1 = std::cmp::max(max_feature1, feature1);
                    max_feature2 = std::cmp::max(max_feature2, feature2);
                }
                S::send_with_count(sender, TestTask2::Select(max_feature1, max_feature2), &task_counter);
            }
            TestTask2::Select(feature1, feature2) => {
                let feature = (feature1 + feature2) / 2;
                S::send_with_count(sender, TestTask2::Max(feature), &task_counter);
            }
            TestTask2::Max(feature) => {
                let ctx = ctx.unwrap();
                *ctx = std::cmp::max(*feature, *ctx);
            }
        };
        Ok(())
    }
}

impl MspcTaskAttr for TestTask2 {
    fn check_specific_name(_name:&String) -> bool { true }
    fn schedule(sched:&MpscTaskScheduler<Self>) -> Result<(), <MpscTaskScheduler<Self> as TaskScheduler<Self>>::Error> {
        let gen_sender = sched.get_specific_sched_sender("generate").unwrap();
        let max_sender = sched.get_specific_sched_sender("max").unwrap();
        let dyn_sender_len = sched.get_dyn_sched_sender().len();
        let dyn_senders = &sched.get_dyn_sched_sender();
        let mut dyn_index = 0;

        sched.send_init_task(TestTask2::Generate);
        for task in sched.get_sched_recv().iter() {
            if task.is_none() { break; }
            let task = task.unwrap();
            match task {
                TestTask2::Generate => gen_sender.send(TestTask2::Generate),
                TestTask2::Roll(data) => 
                    { dyn_index = (dyn_index + 1)%dyn_sender_len; dyn_senders[dyn_index].send(TestTask2::Roll(data)) },
                TestTask2::Select(feature1, feature2) => 
                    { dyn_index = (dyn_index + 1)%dyn_sender_len; dyn_senders[dyn_index].send(TestTask2::Select(feature1, feature2))  },
                TestTask2::Max(feature) => max_sender.send(TestTask2::Max(feature)),
            }.expect("send error");
        }
        Ok(())
    }
}

pub struct GenerateExecutor;
impl TaskExecutor<TestTask2> for GenerateExecutor {
    type Error = TestTaskError;
    fn exec<S:TaskScheduler<TestTask2>>(&mut self, task:TestTask2, sender:&S::Sender, task_counter:Arc<AtomicUsize>) -> Result<(), Self::Error> {
        task.exec::<S>(None, sender, task_counter)
    }
}

pub struct DynExecutor;
impl TaskExecutor<TestTask2> for DynExecutor {
    type Error = TestTaskError;
    fn exec<S:TaskScheduler<TestTask2>>(&mut self, task:TestTask2, sender:&S::Sender, task_counter:Arc<AtomicUsize>) -> Result<(), Self::Error> {
        task.exec::<S>(None, sender, task_counter)
    }
}

pub struct MaxExecutor { max:std::sync::Arc<Mutex<u128>>, tmp_max:u128 }
impl MaxExecutor {
    pub fn new(max:std::sync::Arc<Mutex<u128>>) -> Self { 
        let tmp_max = *max.lock();
        Self { max, tmp_max } 
    }
}
impl TaskExecutor<TestTask2> for MaxExecutor {
    type Error = TestTaskError;
    fn exec<S:TaskScheduler<TestTask2>>(&mut self, task:TestTask2, sender:&S::Sender, task_counter:Arc<AtomicUsize>) -> Result<(), Self::Error> {
        task.exec::<S>(Some(&mut self.tmp_max), sender, task_counter)
    }
}

impl Drop for MaxExecutor {
    fn drop(&mut self) {
        *self.max.lock() = self.tmp_max;
    }
}

pub(crate) fn test_mpsc_dyn_exec() {
    let max_num = Arc::new(Mutex::new(0));
    let mut task_scheduler = MpscTaskScheduler::<TestTask2>::new();
    let gen_exec = GenerateExecutor;
    let dyn_exec1 = DynExecutor;
    let dyn_exec2 = DynExecutor;
    let max_exec = MaxExecutor::new(max_num.clone());
    task_scheduler.register_specific_executor("generate".to_string(), gen_exec);
    task_scheduler.register_specific_executor("max".to_string(), max_exec);
    task_scheduler.register_dyn_executor(dyn_exec1);
    task_scheduler.register_dyn_executor(dyn_exec2);
    
    let now = std::time::Instant::now();
    task_scheduler.schedule().expect("schedule error");
    let task_time = now.elapsed().as_micros();
    println!("max feature:{}", max_num.lock());
    println!("test dyn exec time:{}", task_time);
}